package com.lz.zk.regex;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.lz.zk.git.GitService;
import com.lz.zk.model.ClassModel;
import com.lz.zk.model.MethodModel;
import com.lz.zk.model.ParamModel;

@Service("parserService")
@PropertySource("classpath:regexConfigOfSpring.properties")
public class Parser {

	@Value("${regex.package.nameInfoParser}")
	String regexPackageNameInfoParser; 
	
	@Value("${regex.class.importInfoParser}")
	String regexClassImportInfoParser;
	
	@Value("${regex.class.urlParser}")
	String regexClassUrlParser;
	
	@Value("${regex.class.authorInfoParser}")
	String regexClassAuthorInfoParser;
	
	@Value("${regex.class.versionInfoParser}")
	String regexClassVersionInfoParser;
	
	@Value("${regex.class.nameInfoParser}")
	String regexClassNameInfoParser;
	
	@Value("${regex.class.remarkInfoParser}")
	String regexClassRemarkInfoParser;
	
	@Value("${regex.method.nameInfoParser}")
	String regexMethodNameInfoParser;
	
	@Value("${regex.method.typeInfoParser}")
	String regexMethodTypeInfoParser;
	
	@Value("${regex.method.returnInfoParser}")
	String regexMethodReturnInfoParser;
	
	@Value("${regex.param.remarkInfoParser}")
	String regexParamRemarkInfoParser;
	
	@Value("${regex.param.needInfoParser}")
	String regexParamNeedInfoParser;
	
	@Value("${regex.param.valueInfoParser}")
	String regexParamValueInfoParser;
	
	@Value("${regex.method.sparator}")
	String regexMethodSparator;
	
	@Value("${regex.file.removeParser}")
	String regexFileRemoveParser;
	
	@Value("${regex.file.controllerParser}")
	String regexFileControllerParser;
	
	@Value("${regex.param.devideInfoParser}")
	String regexParamDevideInfoParse;
	
	@Autowired
	private GitService gitService;
	
	ConcurrentHashMap<String, String> local = new ConcurrentHashMap<String, String>();
	
	List<String> requestType = Arrays.asList("GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "TRACE", "Get", "Head", "Post", "Put", "Patch", "Delete", "Options", "Trace");
	/**
	 * 开始构建
	 * @param controllerStrings 控制器源代码
	 * @return
	 */
	public List<ClassModel> startBuild(List<String> controllerStrings){
		List<ClassModel> models = new ArrayList<ClassModel>();
		for(String controller:controllerStrings) {
			String[] removes = regexFileRemoveParser.split("&&");
			for(String remove:removes) {
				controller = controller.replaceAll(remove, " ");
			}
			if(parserByRegexs(regexFileControllerParser,controller)!=null) {
				ClassModel clazz = new ClassModel();
				clazz.setText(controller);
				buildClassInfo(clazz);
				models.add(clazz);
			}else {
				//存为备用类
				String packageName = parserByRegexs(regexPackageNameInfoParser,controller);
				String clazzName = parserByRegexs(regexClassNameInfoParser,controller);
				if(!StringUtils.isEmpty(packageName)&&!StringUtils.isEmpty(clazzName)) 
					local.put(packageName+clazzName, controller);
			}	
		}
		return models;
	}

	/**
	 * 开始构建
	 * @param f 项目路径
	 * @return
	 */
	public List<ClassModel> startBuild(File f){
		List<String> controllers = new ArrayList<String>();
		try {
			getFilesByDir(f,controllers);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return startBuild(controllers);
	}
	
	/**
	 * 开始构建
	 * @param ... git配置
	 * @return
	 */
	public List<ClassModel> startBuild(String baseUrl, String dir, String user, String pass, String branch, String revision){
		gitService.getGitPull(baseUrl, dir, user, pass, branch, revision);
		return startBuild(new File(dir));
	}
	
	/**
	 * 构建类信息，根url，版本，作者等
	 * @param model
	 * @param clazzStr 控制器源码
	 */
	void buildClassInfo(ClassModel model) {
		//TODO 设置类名称，根url。。。
		if(!StringUtils.isEmpty(model.getText())) {
			String str = convertToDeal(model.getText());
			model.setPackageName(parserByRegexs(regexPackageNameInfoParser,str));
			String rootUrl = parserByRegexs(regexClassUrlParser,str);
			model.setAuthor(parserByRegexs(regexClassAuthorInfoParser,str));
			model.setVersion(parserByRegexs(regexClassVersionInfoParser,str));
			model.setName(parserByRegexs(regexClassNameInfoParser,str));
			model.setRemark(parserByRegexs(regexClassRemarkInfoParser,str));
			String methodStr=model.getText().substring(model.getText().indexOf("{") + 1, model.getText().lastIndexOf("}"));
			String[] methods=convertToDeal(methodStr).split(regexMethodSparator);
			model.setMethod(new ArrayList<MethodModel>());
			for(String m:methods) {
				if(!StringUtils.isEmpty(m)&&parserByRegexs(regexClassUrlParser, m)!=null) {
					MethodModel method = new MethodModel();
					method.setMethodUrl(rootUrl==null?"":rootUrl);
					method.setText(m+")");
					buildMethodInfo(method);
					model.getMethod().add(method);
				}
			}
		}
	}
	/**
	 * 构建方法信息，方法url，名称，备注，类型等
	 * @param model
	 * @param methodStr
	 */
	void buildMethodInfo(MethodModel method) {
		//TODO 设置方法url，方法类型。。。
		String str = method.getText();
		if(!StringUtils.isEmpty(str)) {
			String url = parserByRegexs(regexClassUrlParser, str);
			method.setMethodUrl((method.getMethodUrl()+"/"+(url ==null?"":url)).replace("//", "/"));
			method.setMethodRealUrl(method.getMethodUrl());
			String type = parserByRegexs(regexMethodTypeInfoParser,str);
			if(type!=null) {
				for(String requestTyp : requestType) {
					if(type.toUpperCase().endsWith(requestTyp)) {
						method.setMethodType(requestTyp);
					}
				}
			}
			method.setMethodRemark(parserByRegexs(regexClassRemarkInfoParser,str));
			//model.setMethodName(parserByRegexs(regexClassRemarkInfoParser,str));
			
			String paramM = getParamStr(str);
			method.setMethodParam(new ArrayList<ParamModel>());
			List<String> params=getRealArr(Arrays.asList(paramM.split(",")),m->{return countCharAppear(m,Arrays.asList('(',')'))%2!=0 || countCharAppear(m,Arrays.asList('('))!=countCharAppear(m,Arrays.asList(')')) || countCharAppear(m,Arrays.asList('<','>'))%2!=0 || countCharAppear(m,Arrays.asList('<'))!=countCharAppear(m,Arrays.asList('>'));},n->{return countCharAppear(n,Arrays.asList('(',')'))%2==0 && countCharAppear(n,Arrays.asList('('))==countCharAppear(n,Arrays.asList(')')) && countCharAppear(n,Arrays.asList('<','>'))%2==0 && countCharAppear(n,Arrays.asList('<'))==countCharAppear(n,Arrays.asList('>'));});
			for(String m:params) {
				ParamModel param = new ParamModel();
				param.setText(m);
				buildParamInfo(param);
				param.getParamName().replaceAll("\\[", "\\\\\\\\[").replaceAll("\\]", "\\\\\\\\]");
				param.setParamRemark(parserByRegexs(".*?@param.*?"+(param.getParamName())+"(.*?)\\*", str));
				method.getMethodParam().add(param);
			}
			
			String mn = str.replaceAll(paramM, "");
			if(mn.lastIndexOf("(")!=-1) mn=mn.substring(0, mn.lastIndexOf("("));
			List<String> abc = getRealArr(Arrays.asList(mn.split("[,| ]")),m->{return (countCharAppear(m,Arrays.asList('<','>'))%2!=0 || countCharAppear(m,Arrays.asList('<'))!=countCharAppear(m,Arrays.asList('>')));},
					n->{return countCharAppear(n,Arrays.asList('<','>'))%2==0 && countCharAppear(n,Arrays.asList('<'))==countCharAppear(n,Arrays.asList('>'));});
			method.setMethodName(abc.get(0));
			method.setMethodReturn(abc.get(1));
			method.setMethodReturnRemark(parserByRegexs(regexMethodReturnInfoParser, str));
		}
	}
	/**
	 * 构建参数信息，参数类型，参数默认值，参数名称等
	 * @param model
	 * @param paramStr
	 */
	void buildParamInfo(ParamModel param) {
		//TODO 设置参数名称，类型，默认值。。。
		String paramStr=param.getText();
		//提取参数名和参数类型
		String[] tempP = new String[] {};
		tempP = paramStr.split(regexParamDevideInfoParse);
		for (int t = tempP.length - 1; t > 0; t--) {
			if (tempP[t] != null && (countCharAppear(tempP[t],Arrays.asList('<','>'))%2!=0 || countCharAppear(tempP[t],Arrays.asList('<'))!=countCharAppear(tempP[t],Arrays.asList('>')))) {
				int m = t;
				while (m-- > 0) {
					tempP[t] = tempP[m] + "," + tempP[t];
					if (countCharAppear(tempP[t],Arrays.asList('<','>'))%2==0 && countCharAppear(tempP[t],Arrays.asList('<'))==countCharAppear(tempP[t],Arrays.asList('>'))) {
						t = m;
						tempP[m] = null;
						break;
					}
					tempP[m] = null;
				}
			}
		}
		int x = tempP.length;
		while(--x>=0) {
			if(!StringUtils.isEmpty(tempP[x])) {
				param.setParamName(tempP[x]);
				break;
			}
		}
		while(--x>=0) {
			if(!StringUtils.isEmpty(tempP[x])) {
				param.setParamType(tempP[x]);	
				break;
			}
		}
		//提取默认值
		param.setParamValue(parserByRegexs(regexParamValueInfoParser, paramStr));
		//提取是否必须
		param.setParamValue(parserByRegexs(regexParamNeedInfoParser, paramStr));
		if ((param.getParamNeed()!=null && (param.getParamNeed().indexOf("false") != -1))
				|| (paramStr.indexOf("defaultValue") != -1)
				|| (paramStr.indexOf("@") == -1)) {
			param.setParamNeed("false");
		} else {
			param.setParamNeed("true");
		}
		//提取默认值
		param.setParamValue(parserByRegexs(regexParamValueInfoParser, paramStr));
	}
	
	/**
	 * 匹配字符串中符合正则的字符串或数组
	 * @param regexs 正则集合
	 * @param str 待匹配字符串
	 * @return
	 */
	String parserByRegexs(String regexArr,String str) {
		String[] regexs = regexArr.split("\\|\\|");
		for(String regex:regexs) {
			Pattern pattern = Pattern.compile(regex);
			Matcher matcher = pattern.matcher(str);
			if(matcher.find())
				return matcher.group(1);
		}
		return null;
	}
	
	/**
	 * 匹配字符串中符合正则的字符串或数组
	 * @param regexs 正则集合
	 * @param str 待匹配字符串
	 * @return
	 */
	String parserByRegexsAnd(String regexArr,String str) {
		String[] regexs = regexArr.split("&&");
		for(String regex:regexs) {
			Pattern pattern = Pattern.compile(regex);
			Matcher matcher = pattern.matcher(str);
			if(matcher.find())
				str = matcher.group(1);
			else
				return null;
		}
		return str;
	}
	
	void getFilesByDir(File f, List<String> fileStrs) throws IOException {
		System.out.println("扫描文件：" + f.getAbsolutePath());
		if (f.exists()) {
			if (f.isFile() && f.getAbsolutePath().endsWith(".java")) {
				StringBuffer buffer = new StringBuffer();
				BufferedReader bf = new BufferedReader(new FileReader(f));
				String s = null;
				while ((s = bf.readLine()) != null) {
					// 使用readLine方法，一次读一行
					buffer.append(s.trim()).append(" ");
				}
				fileStrs.add(buffer.toString());
			} else if (f.isDirectory()) {
				for (File file : f.listFiles()) {
					getFilesByDir(file, fileStrs);
				}
			}
		}
	}
	
	/**
	 * 方法体去掉
	 * 
	 * @param controller
	 * @return
	 */
	 String convertToDeal(String controller) {
		// System.out.println(controller);
		List<Integer> a = new ArrayList<Integer>();
		List<Integer> b = new ArrayList<Integer>();
		List<Integer> c = new ArrayList<Integer>();
		List<Integer> d = new ArrayList<Integer>();
		for (int i = 0; i < controller.length(); i++) {
			if ("{".charAt(0) == (controller.charAt(i))) {
				a.add(i);
			}
			if ("}".charAt(0) == (controller.charAt(i))) {
				b.add(i);
			}
			if (i > 0 && "{".charAt(0) == (controller.charAt(i)) && "/".charAt(0) == (controller.charAt(i - 1))) {
				d.add(i);
			}
			int t = i;
			while (t-- > 0) {
				if ("(".charAt(0) == (controller.charAt(t))) {
					d.add(i);
				}
				if (")".charAt(0) == (controller.charAt(t))) {
					break;
				}
			}
		}
		for (int j = 0; j < b.size(); j++) {
			for (int k = a.size() - 1; k > -1; k--) {
				if (!c.contains(a.get(k)) && b.get(j) > a.get(k)) {
					c.add(a.get(k));
					c.add(b.get(j));
					break;
				}
			}
		}
		for (int l = c.size() - 1; l > 0; l = l - 2) {
			int flag = 0;
			for (int m = 0; m < c.size(); m = m + 2) {
				if ((c.get(m + 1) > c.get(l) && c.get(m) < c.get(l - 1))) {
					flag = 1;
				}
			}
			if (flag == 0 && !d.contains(c.get(l - 1))) {
				String x = controller.substring(0, c.get(l - 1) + 1);
				String y = controller.substring(c.get(l));
				controller = x + y;
			}
		}
		return controller;
	}
	 
		/**
		 * <截取参数string>
		 * 
		 * @param str
		 * @return
		 */
		private static String getParamStr(String str) {
			List<Integer> indexs = new ArrayList<Integer>();
			for (int i = 0; i < str.length(); i++) {
				if ("(".equals(str.charAt(i) + "") || ")".equals(str.charAt(i) + "")) {
					indexs.add(i);
				}
			}
			if (indexs.size() <= 2) {
				return "";
			}
			for (int j = indexs.size() - 2; j > 0; j--) {
				if (")".equals("" + str.charAt(indexs.get(j)))) {
					j--;
				} else {
					return str.substring(indexs.get(j) + 1, indexs.get(indexs.size() - 1));
				}
			}
			return str;
		}
		
		public static List<String> getRealArr(List<String> tempP,Function<String,Boolean> f1,Function<String,Boolean> f2) {
			List<String> arr = new ArrayList<String>();
			for (int t = tempP.size() - 1; t >= 0; t--) {
				if (tempP.get(t) != null && !StringUtils.isEmpty(tempP.get(t)) && f1.apply(tempP.get(t))) {
					int m = t;
					while (m-- > 0) {
						if(tempP.get(m)==null||StringUtils.isEmpty(tempP.get(m))) {
							continue;
						}
						tempP.set(t, tempP.get(m) + "," + tempP.get(t));
						if (f2.apply(tempP.get(t))) {
							t = m;
							tempP.set(m, null);
							break;
						}
						tempP.set(m, null);
					}
				}
			}
			for (int t = tempP.size() - 1; t >= 0; t--) {
				if(!StringUtils.isEmpty(tempP.get(t))) {
					arr.add(tempP.get(t));
				}
			}
			return arr;
		}
		
		static int countCharAppear(String str,List<Character> chars) {
			int sum=0;
			for(int i=0;i<str.length();i++) {
				if(chars.contains(str.charAt(i))) {
					sum++;
				}
			}
			return sum;
		}

}
